/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.webanovare.bb;

import com.webanovare.model.GamesRegistry;
import com.webanovare.model.UserRegistry;
import com.webanovare.model.db.PlayedGame;
import com.webanovare.model.db.User;
import com.webanovare.ruzzle.mgr.GameManager;
import com.webanovare.ruzzle.mgr.impl.IGame;
import com.webanovare.ruzzle.solver.Engine;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
import org.icefaces.application.PushRenderer;

/**
 *
 * @author expert
 */
@ManagedBean(name = "board")
@SessionScoped
public class BoardBB implements Serializable {

    final private static String REDIRECT_GAME = "board.xhtml";
    private String PUSH_GROUP;
    private IGame game = null;
    private Long gid = 0L;
    PlayedGameBB pgbb;
    Engine engine;
    @EJB
    GamesRegistry gr;
    @EJB
    UserRegistry ur;

    public BoardBB() {
    }

    private boolean isGameRunning() {
        return this.game != null;
    }

    public int getOpponentPoints() {

        return this.isGameRunning() ? this.game.getOpponentPoints() : -1;
    }

    public int getOwnerPoints() {
        return this.isGameRunning() ? this.game.getOwnerPoints() : -1;
    }

    public IGame getGame() {
        return this.game;
    }

    public void setGame(IGame g) {
        this.game = g;
        this.gid = new Long(g.getGameId());
    }

    public List<String> getOpponentWords() {
        List<String> words = new ArrayList<>();
        Map<String, Integer> stats = this.game.getOpponentStatistics();
        for (String s : stats.keySet()) {
            words.add(s);
        }

        return words;
    }

    public List<Integer> getOpponentWordScore() {
        List<Integer> points = new ArrayList<>();
        for (int i : this.game.getOpponentStatistics().values()) {
            points.add(i);
        }
        return points;
    }

    public List<Integer> getOwnerWordScore() {
        List<Integer> points = new ArrayList<>();
        for (int i : this.game.getOwnerStatistics().values()) {
            points.add(i);
        }
        return points;
    }

    public List<String> getOwnerWords() {
        List<String> words = new ArrayList<>();
        Map<String, Integer> stats = this.game.getOwnerStatistics();
        for (String s : stats.keySet()) {
            words.add(s);
        }

        return words;
    }

    public List<String> getOwnerWordsScores() {
        List<String> out = new ArrayList<>();
        Map<String, Integer> stats = this.game.getOwnerStatistics();
        for (String s : stats.keySet()) {
            String ss = stats.get(s) + " " + s;
            out.add(ss);
        }
        Collections.sort(out);
        Collections.reverse(out);
        return out;
    }

    public List<String> getOpponentWordsScores() {
        List<String> out = new ArrayList<>();
        Map<String, Integer> stats = this.game.getOpponentStatistics();
        for (String s : stats.keySet()) {
            String ss = stats.get(s) + " " + s;
            out.add(ss);
        }
        Collections.sort(out);
        Collections.reverse(out);
        return out;
    }

    public void setPushGroup(String gameId) {
        this.PUSH_GROUP = gameId + "";
    }

    public int getGameId() {
        if (this.game == null) {
            return 0;
        }
        return this.game.getGameId();
    }

    public String getOpponent() {
        return this.isGameRunning() ? this.game.getOpponent().toString() : "";
    }

    public String getOwner() {
        return this.isGameRunning() ? this.game.getOwner().toString() : "";
    }

    public int getMinutes() {
        return this.isGameRunning() ? this.game.getTimeSettings().getMinutes() : 0;
    }

    public int getSeconds() {
        return this.isGameRunning() ? this.game.getTimeSettings().getSeconds() : 0;
    }

    public int getSize() {
        return this.isGameRunning() ? this.game.getSize() : 0;
    }

    public String getWinner() {
        if (this.getOwnerPoints() > this.getOpponentPoints()) {
            return this.getOwner();
        } else if (this.getOwnerPoints() < this.getOpponentPoints()) {
            return this.getOpponent();
        } else {
            return "";
        }
    }

    public String getLoser() {
        if (this.getOwnerPoints() < this.getOpponentPoints()) {
            return this.getOwner();
        } else if (this.getOwnerPoints() > this.getOpponentPoints()) {
            return this.getOpponent();
        } else {
            return "";
        }
    }

    public int getWinnerPoints() {
        String winner = this.getWinner();
        if (winner.equals(this.getOwner())) {
            return this.getOwnerPoints();
        } else {
            return this.getOpponentPoints();
        }
    }

    public int getLoserPoints() {
        String winner = this.getWinner();
        if (winner.equals(this.getOwner())) {
            return this.getOpponentPoints();
        } else {
            return this.getOwnerPoints();
        }
    }

    public List<String> getWinnerWords() {
        String winner = this.getWinner();
        if (winner.equals(this.getOwner())) {
            return this.getOwnerWords();
        } else {
            return this.getOpponentWords();
        }
    }

    public List<String> getLoserWords() {
        String winner = this.getWinner();
        if (winner.equals(this.getOwner())) {
            return this.getOpponentWords();
        } else {
            return this.getOwnerWords();
        }
    }

    public boolean hasOpponent() {
        if (this.game != null && this.game.isActive()) {
            if (this.game.getOpponent() != null) {
                try {
                    FacesContext fc = FacesContext.getCurrentInstance();
                    fc.getExternalContext().redirect(REDIRECT_GAME);
                } catch (IOException ex) {
                    Logger.getLogger(BoardBB.class.getName()).log(Level.SEVERE,
                            "Fatal: " + REDIRECT_GAME + " couldn't be found", ex);
                }
            }
        }

        return true;
    }

    public String getBoard() {
        if (this.isGameRunning()) {
            List<Character> board = this.game.getBoard();
            StringBuilder b = new StringBuilder();
            for (char c : board) {
                b.append(c);
            }

            return b.toString();
        }
        return "";
    }

    public List<String> getAllWords() {
        try {
            engine = new Engine(this.game.getBoardMatrix(), this.game.getTrie());
        } catch (FileNotFoundException ex) {
            Logger.getLogger(BoardBB.class.getName()).log(Level.SEVERE, null, ex);
        }
        return engine.getWords();
    }

    public void endGame() {
        if (this.isGameRunning()) {
            try {
                storeGame();
                PushRenderer.removeCurrentSession(this.PUSH_GROUP);
                GameManager.getInstance().endGame(this.game.getGameId());

                this.game = null;
                FacesContext fc = FacesContext.getCurrentInstance();
                fc.getExternalContext().redirect("game.xhtml");
            } catch (IOException ex) {
                Logger.getLogger(BoardBB.class.getName()).log(Level.SEVERE, null, ex);
            }
        }



    }

    public void storeGame() {
        if (this.game != null) {
            User owner = ur.findUser(this.getOwner());
            User opponent = ur.findUser(this.getOpponent());
            if (owner != null && opponent != null) {
                if (gr.getById(gid) == null) {
                    boolean didOwnerWin = (this.getWinner().equals((this.getOwner())));
                    PlayedGame thisGame = new PlayedGame(gid, owner, opponent,
                            this.getWinnerPoints(), this.getLoserPoints(), this.getWinnerWords(), this.getLoserWords(), didOwnerWin);
                    gr.add(thisGame);
                    owner.addPlayedGame(thisGame);
                    ur.update(owner);
                    opponent.addPlayedGame(thisGame);
                    ur.update(opponent);
                }
            }


        }
    }

    public void send() {
        PushRenderer.render(this.PUSH_GROUP);
    }
}
